package chat

import (
	"context"
	"mychat/api"
	"time"

	"mychat/internal/common/cmctx"
	"mychat/internal/common/errors"
	"mychat/internal/common/logger"
	"mychat/internal/data"
	"mychat/internal/data/mongo"
)

type ChatService interface {
	NewChat(ctx context.Context, req *api.NewChatRequest) (*api.NewChatReply, *errors.Error)
	GetChat(ctx context.Context, chatId string) (*api.GetChatReply, *errors.Error)
	ListChats(ctx context.Context, req *api.ListChatRequest) (*api.ListChatReply, *errors.Error)
	ChangeChatName(ctx context.Context, req *api.ChangeChatNameRequest) (*api.ChangeChatNameReply, *errors.Error)
	DeleteChat(ctx context.Context, req *api.DeleteChatRequest) (*api.DeleteChatReply, *errors.Error)
	ChatInviteFriend(ctx context.Context, req *api.InviteFreindRequest) (*api.InviteFreindReply, *errors.Error)
	ChatRemoveFriend(ctx context.Context, req *api.RemoveFreindRequest) (*api.RemoveFreindReply, *errors.Error)
}

type chatService struct {
	lg   logger.Logger
	data *data.Data
}

func NewChatService(lg logger.Logger, dt *data.Data) ChatService {
	return &chatService{
		data: dt,
		lg:   lg.WithCustomTag("_chat_service"),
	}
}

// chat
// @Summary 新建聊天
// @Description 应该通过ws请求
// @Tags chat
// @Accept json
// @Param name body api.NewChatRequest true "新建聊天"
// @Produce json
// @Success 200 {object} api.NewChatRequest
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Router /v1/mgchat/chat [post]
func (s *chatService) NewChat(ctx context.Context, req *api.NewChatRequest) (*api.NewChatReply, *errors.Error) {
	userId := cmctx.GetCtxUserId(ctx)

	ids := []uint{userId, uint(req.FriendId)}
	userlist, err := s.data.UserDao.ListUserWithIds(ctx, ids)
	if err != nil {
		s.lg.Error(ctx, "UserDao.ListUserWithIds failed||ids=%v||err=%v", ids, err)
		return nil, &errors.DefaultError
	}

	userMap := make(map[uint]string)
	for _, u := range userlist {
		userMap[u.ID] = u.Name
	}

	_, ok := userMap[uint(req.FriendId)]
	if !ok {
		return nil, &errors.UserInvalidError
	}

	var mchat = mongo.Chat{
		Users:     nil,
		Owner:     userId,
		ChatName:  userMap[uint(req.FriendId)],
		CreatedAt: time.Now(),
	}

	for key, val := range userMap {
		mchat.Users = append(mchat.Users, mongo.ChatUser{UserId: key, Name: val})
	}

	err = s.data.Mongo.CreateChat(ctx, &mchat)
	if err != nil {
		s.lg.Error(ctx, "mongo.CreateChat failed||chat=%v||err=%v", mchat, err)
		return nil, &errors.DefaultError
	}

	return &api.NewChatReply{
		ChatId: mchat.ChatId,
	}, nil
}

// chat
// @Summary 获取聊天信息
// @Description
// @Tags chat
// @Accept x-www-form-urlencoded
// @Param chatid path string true "chatid"
// @Produce json
// @Success 200 {object} api.GetChatReply
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Router /v1/mgchat/chat [get]
func (s chatService) GetChat(ctx context.Context, chatId string) (*api.GetChatReply, *errors.Error) {
	cht, err := s.data.Mongo.GetChat(ctx, chatId)
	if err != nil {
		s.lg.Error(ctx, "mongo.GetChat failed||chatId=%v||err=%v", chatId, err)
		return nil, &errors.DefaultError
	}

	if cht == nil {
		return nil, &errors.ChatNotExist
	}

	var chtUsers []*api.ChatUser
	for _, cu := range cht.Users {
		chtUsers = append(chtUsers, &api.ChatUser{
			UserId: uint32(cu.UserId),
			Name:   cu.Name,
		})
	}

	return &api.GetChatReply{
		Chat: &api.Chat{
			Owner:    uint32(cht.Owner),
			ChatId:   cht.ChatId,
			Users:    chtUsers,
			ChatName: cht.ChatName,
		},
	}, nil
}

// chat
// @Summary 批量获取聊天信息
// @Description
// @Tags chat
// @Accept x-www-form-urlencoded
// @Param pageIndex query int true "页数"
// @Param pageSize query int true "每页数量"
// @Produce json
// @Success 200 {object} api.ListChatReply
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Router /v1/mgchat/chats [get]
func (s *chatService) ListChats(ctx context.Context, req *api.ListChatRequest) (*api.ListChatReply, *errors.Error) {
	userId := cmctx.GetCtxUserId(ctx)

	param := mongo.GetChatsParam{
		UserId: userId,
	}

	if req.PageSize > 0 {
		if req.PageIndex > 0 {
			param.Skip = (req.PageIndex - 1) * req.PageSize
		}
		param.Limit = req.PageSize
	}

	total, mchats, err := s.data.Mongo.ListChats(ctx, &param)
	if err != nil {
		s.lg.Error(ctx, "mongo.GetChats failed||param=%v||err=%v", param, err)
		return nil, &errors.DefaultError
	}

	var chatList []*api.Chat
	for _, c := range mchats {
		chatList = append(chatList, &api.Chat{
			Owner:    uint32(c.Owner),
			ChatId:   c.ChatId,
			ChatName: c.ChatName,
		})
	}

	return &api.ListChatReply{
		Total: total,
		List:  chatList,
	}, nil
}

// chat
// @Summary 删除聊天
// @Description
// @Tags chat
// @Accept json
// @Param param body api.DeleteChatRequest true "结构体"
// @Produce json
// @Success 200 {object} api.DeleteChatReply
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Router /v1/mgchat/chats [delete]
func (s *chatService) DeleteChat(ctx context.Context, req *api.DeleteChatRequest) (*api.DeleteChatReply, *errors.Error) {
	userId := cmctx.GetCtxUserId(ctx)

	cht, err := s.data.Mongo.GetChat(ctx, req.ChatId)
	if err != nil {
		s.lg.Error(ctx, "mongo.GetChat failed||chatId=%v||err=%v", req.ChatId, err)
		return nil, &errors.DefaultError
	}

	if cht == nil {
		return &api.DeleteChatReply{
			DeletedAt: time.Now().Unix(),
		}, nil
	}

	if cht.Owner != userId {
		return nil, &errors.ChatForbiddenError
	}

	err = s.data.Mongo.DeleteChat(ctx, req.ChatId)
	if err != nil {
		s.lg.Error(ctx, "mongo.DeleteChat failed||chatId=%v||err=%v", req.ChatId, err)
		return nil, &errors.DefaultError
	}

	return &api.DeleteChatReply{DeletedAt: time.Now().Unix()}, nil
}

// chat
// @Summary 聊天移除好友
// @Description
// @Tags chat
// @Accept json
// @Param param body api.RemoveFreindRequest true "结构体"
// @Produce json
// @Success 200 {object} api.RemoveFreindReply
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Router /v1/mgchat/chat/remove [put]
func (s *chatService) ChatRemoveFriend(ctx context.Context, req *api.RemoveFreindRequest) (*api.RemoveFreindReply, *errors.Error) {
	userId := cmctx.GetCtxUserId(ctx)

	cht, err := s.data.Mongo.GetChat(ctx, req.ChatId)
	if err != nil {
		s.lg.Error(ctx, "mongo.GetChat failed||chatId=%v||err=%v", req.ChatId, err)
		return nil, &errors.DefaultError
	}

	if cht == nil {
		return nil, &errors.ChatNotExist
	}

	if cht.Owner != userId {
		return nil, &errors.ChatForbiddenError
	}

	err = s.data.Mongo.DeleteChatMember(ctx, req.ChatId, uint(req.FriendId))
	if err != nil {
		s.lg.Error(ctx, "mongo.DeleteChatMember failed||chatId=%v||memeberId=%v||err=%v",
			req.ChatId, req.FriendId, err)
		return nil, &errors.DefaultError
	}

	var friendName string
	var chatUser []*api.ChatUser
	for _, cu := range cht.Users {
		if uint32(cu.UserId) == req.FriendId {
			friendName = cu.Name
		} else {
			chatUser = append(chatUser, &api.ChatUser{
				UserId: uint32(cu.UserId),
				Name:   cu.Name,
			})
		}
	}

	return &api.RemoveFreindReply{
		FriendId:   req.FriendId,
		FriendName: friendName,
		ChatUsers:  chatUser,
	}, nil
}

// chat
// @Summary 聊天邀请好友
// @Description
// @Tags chat
// @Accept json
// @Param param body api.InviteFreindRequest true "结构体"
// @Produce json
// @Success 200 {object} api.InviteFreindReply
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Router /v1/mgchat/chat/invite [put]
func (s *chatService) ChatInviteFriend(ctx context.Context, req *api.InviteFreindRequest) (*api.InviteFreindReply, *errors.Error) {
	cht, err := s.data.Mongo.GetChat(ctx, req.ChatId)
	if err != nil {
		s.lg.Error(ctx, "mongo.GetChat failed||chatId=%v||err=%v", req.ChatId, err)
		return nil, &errors.DefaultError
	}

	if cht == nil {
		return nil, &errors.ChatNotExist
	}

	ufriend, err := s.data.UserDao.GetUser(ctx, uint(req.FriendId))
	if err != nil {
		s.lg.Error(ctx, "userDao.GetUser failed||userId=%v||err=%v", req.FriendId, err)
		return nil, &errors.DefaultError
	}

	if ufriend == nil {
		return nil, &errors.FriendInvalidError
	}

	muser := &mongo.ChatUser{
		UserId: ufriend.ID,
		Name:   ufriend.Name,
	}
	err = s.data.Mongo.AddChatMember(ctx, req.ChatId, muser)
	if err != nil {
		s.lg.Error(ctx, "mongo.AddChatMember failed||chatId=%v||memberId=%v||err=%v",
			req.ChatId, req.FriendId, err)
		return nil, &errors.DefaultError
	}

	var chatUsers = []*api.ChatUser{
		//{
		//	UserId: uint32(ufriend.ID),
		//	Name:   ufriend.Name,
		//},
	}
	for _, cu := range cht.Users {
		chatUsers = append(chatUsers, &api.ChatUser{
			UserId: uint32(cu.UserId),
			Name:   cu.Name,
		})
	}
	return &api.InviteFreindReply{
		FriendId:   uint32(ufriend.ID),
		FriendName: ufriend.Name,
		ChatUsers:  chatUsers,
	}, nil
}

// chat
// @Summary 变更聊天名称
// @Description
// @Tags chat
// @Accept json
// @Param param body api.ChangeChatNameRequest true "结构体"
// @Produce json
// @Success 200 {object} api.ChangeChatNameReply
// @Failure 400 {object} errors.Error
// @Failure 404 {object} errors.Error
// @Router /v1/mgchat/chat [patch]
func (s *chatService) ChangeChatName(ctx context.Context, req *api.ChangeChatNameRequest) (*api.ChangeChatNameReply, *errors.Error) {
	userId := cmctx.GetCtxUserId(ctx)
	cht, err := s.data.Mongo.GetChat(ctx, req.ChatId)
	if err != nil {
		s.lg.Error(ctx, "mongo.GetChat failed||chatId=%v||err=%v", req.ChatId, err)
		return nil, &errors.DefaultError
	}

	if cht == nil {
		return nil, &errors.ChatNotExist
	}

	if cht.ChatName == req.NewName {
		return &api.ChangeChatNameReply{
			UpdatedAt: time.Now().Unix(),
		}, nil
	}

	if cht.Owner != userId {
		return nil, &errors.ChatForbiddenError
	}

	err = s.data.Mongo.ChangeChatName(ctx, req.ChatId, req.NewName)
	if err != nil {
		s.lg.Error(ctx, "mongo.ChangeChatName failed||err=%v", req.ChatId, err)
		return nil, &errors.DefaultError
	}

	return &api.ChangeChatNameReply{UpdatedAt: time.Now().Unix()}, nil
}
